package com.guigarage.gestures;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JComponent;

/**
 * Do not refer to this class in your code. Always use
 * <code>GestureUtilities</code>. This class is NOT platform independent
 * 
 * @author hendrikebbers
 * @see GestureUtilities
 */
@SuppressWarnings("restriction")
public class NativeGestureUtilities {

	// TODO: Wenn die JComponent im Listener referenziert ist, wird sie nicht
	// weggeräumt...

	private static Map<WeakReference<JComponent>, Map<GestureListener, com.apple.eawt.event.GestureAdapter>> linkMap;

	private NativeGestureUtilities() {
	}

	protected static synchronized void add(JComponent comp,
			GestureListener listener) throws GesturesNotSupportedException {
		try {
			if (linkMap == null) {
				linkMap = new HashMap<WeakReference<JComponent>, Map<GestureListener, com.apple.eawt.event.GestureAdapter>>();
			}
			WeakReference<JComponent> compRef = getOrCreateReference(comp);
			Map<GestureListener, com.apple.eawt.event.GestureAdapter> listenerLinkMap = linkMap
					.get(compRef);
			if (listenerLinkMap == null) {
				listenerLinkMap = new HashMap<GestureListener, com.apple.eawt.event.GestureAdapter>();
				linkMap.put(compRef, listenerLinkMap);
			}
			GestureAdapter adapter = new GestureAdapter(compRef, listener);
			com.apple.eawt.event.GestureUtilities.addGestureListenerTo(comp,
					adapter);
			listenerLinkMap.put(listener, adapter);
		} catch (Exception e) {
			throw new GesturesNotSupportedException(e);
		}
	}

	protected static synchronized void remove(JComponent comp,
			GestureListener listener) throws GesturesNotSupportedException {
		try {
			if (linkMap != null) {
				WeakReference<JComponent> compRef = getAvailableReference(comp);
				if (compRef != null) {
					Map<GestureListener, com.apple.eawt.event.GestureAdapter> listenerLinkMap = linkMap
							.get(compRef);
					if (listenerLinkMap != null) {
						com.apple.eawt.event.GestureAdapter adapter = listenerLinkMap
								.get(listener);
						if (adapter != null) {
							com.apple.eawt.event.GestureUtilities
									.removeGestureListenerFrom(comp, adapter);
						}
						listenerLinkMap.remove(listener);
						if (listenerLinkMap.isEmpty()) {
							linkMap.remove(compRef);
						}
					}
				}
			}
		} catch (Exception e) {
			throw new GesturesNotSupportedException(e);
		}
	}

	private static WeakReference<JComponent> getOrCreateReference(
			JComponent component) {
		WeakReference<JComponent> ret = getAvailableReference(component);
		if (ret == null) {
			ret = new WeakReference<JComponent>(component);
		}
		return ret;
	}

	private static WeakReference<JComponent> getAvailableReference(
			JComponent component) {
		WeakReference<JComponent> ret = null;

		List<WeakReference<JComponent>> emptyReferences = null;
		for (WeakReference<JComponent> ref : linkMap.keySet()) {
			JComponent comp = ref.get();
			if (comp == null) {
				if (emptyReferences == null) {
					emptyReferences = new ArrayList<WeakReference<JComponent>>();
				}
				emptyReferences.add(ref);
			} else if (ret != null && comp.equals(component)) {
				ret = ref;
			}
		}
		if (emptyReferences != null && !emptyReferences.isEmpty()
				&& linkMap != null) {
			for (WeakReference<JComponent> ref : emptyReferences) {
				linkMap.remove(ref);
			}
		}
		return ret;
	}

	private static synchronized void remove(
			WeakReference<JComponent> compReference) {
		if (linkMap != null) {
			linkMap.remove(compReference);
		}
	}

	private static class GestureAdapter extends
			com.apple.eawt.event.GestureAdapter {

		private GestureListener listener;

		private WeakReference<JComponent> compReference;

		public GestureAdapter(WeakReference<JComponent> compReference,
				GestureListener listener) {
			this.listener = listener;
			this.compReference = compReference;
		}

		@Override
		public void gestureBegan(com.apple.eawt.event.GesturePhaseEvent event) {
			if (listener instanceof GesturePhaseListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GesturePhaseListener) listener)
							.gestureBegan(new GesturePhaseEvent(comp));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}

		@Override
		public void gestureEnded(com.apple.eawt.event.GesturePhaseEvent event) {
			if (listener instanceof GesturePhaseListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GesturePhaseListener) listener)
							.gestureEnded(new GesturePhaseEvent(comp));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}

		@Override
		public void magnify(com.apple.eawt.event.MagnificationEvent event) {
			if (listener instanceof GestureMagnificationListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GestureMagnificationListener) listener)
							.magnify(new GestureMagnificationEvent(comp, event
									.getMagnification()));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}

		@Override
		public void rotate(com.apple.eawt.event.RotationEvent event) {
			if (listener instanceof GestureRotationListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GestureRotationListener) listener)
							.rotate(new GestureRotationEvent(comp, event
									.getRotation()));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}

		@Override
		public void swipedDown(com.apple.eawt.event.SwipeEvent event) {
			if (listener instanceof GestureSwipeListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GestureSwipeListener) listener)
							.swipedDown(new GestureSwipeEvent(comp));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}

		@Override
		public void swipedLeft(com.apple.eawt.event.SwipeEvent event) {
			if (listener instanceof GestureSwipeListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GestureSwipeListener) listener)
							.swipedLeft(new GestureSwipeEvent(comp));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}

		@Override
		public void swipedRight(com.apple.eawt.event.SwipeEvent event) {
			if (listener instanceof GestureSwipeListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GestureSwipeListener) listener)
							.swipedRight(new GestureSwipeEvent(comp));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}

		@Override
		public void swipedUp(com.apple.eawt.event.SwipeEvent event) {
			if (listener instanceof GestureSwipeListener) {
				JComponent comp = compReference.get();
				if (comp != null) {
					((GestureSwipeListener) listener)
							.swipedUp(new GestureSwipeEvent(comp));
				} else {
					listener = null;
					remove(compReference);
				}
			}
		}
	}
}
